 /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package net.worlds.lua;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.worlds.Main;
import net.worlds.object.Script;
import se.krka.kahlua.luaj.compiler.LuaCompiler;
import se.krka.kahlua.vm.LuaClosure;
import se.krka.kahlua.vm.LuaState;


public class ScriptThread{
    private LuaState state;
    private String source;
    private String name;
    private Thread thread;
    public ArrayList<Event> linkedEvents = new ArrayList<Event>(8);
    public Script script;
    private final ArrayList<Runnable> tasks = new ArrayList<Runnable>(128);
    public ScriptThread(Script scr, LuaState state, String name, String source)
    {
        this.script = scr;
        this.state = state;
        this.source = source;
        this.name = name;
        state.getEnvironment().rawset("link", new GlobalFunctions.LinkFunction(state, this));
    }
    public LuaState getLuaState()
    {
        return state;
    }
    public void start()
    {
        state.st = this;
        Runnable r = new Runnable()
        {
            public void run() {
                try
                {
                LuaClosure c = null;
                try {
                    c = LuaCompiler.loadstring(source, name, state.getEnvironment());
                } catch (IOException ex) {
                    ex.printStackTrace();
                    return;
                }
                synchronized(state.getEnvironment())
                {
                    state.call(c, null);
                }
                if(linkedEvents.isEmpty())
                    return;
                while(!state.stopped)
                {
                    processTasks();
                    synchronized(tasks)
                    {
                        try {
                            tasks.wait();
                        } catch (InterruptedException ex) {
                            return;
                        }
                    }
                }
                }
                catch(Exception ex)
                {
                    handleExceptions(ex, state);
                }
            }
        };
        Main.getScriptContext().run(r);
    }
    public void unlinkEvents()
    {
        Iterator<Event> itr = linkedEvents.iterator();
        while(itr.hasNext())
        {
            Event e = itr.next();
            e.destroyConnectionsFor(state);
            itr.remove();
        }
    }
    public void stop()
    {
        state.stopped = true;
        synchronized(tasks)
        {
            tasks.notify();
        }
    }
    public void handleExceptions(Exception ex, LuaState state)
    {
        stop();
        String line = state.currentThread.stackTrace.split("\\n")[0];
        String[] parts = line.split(":");
        if(parts.length == 2)
            line = parts[1];
        String start = name+":"+line+": ";
        //ex.printStackTrace();
        if(ex.toString().contains(name))
            start = "";
        if(ex instanceof RuntimeException && ex.getMessage() != null)
            Main.log(start+ex.getMessage());
        else
            Main.log(start+ex.toString());
        if(!(ex instanceof RuntimeException) || ex instanceof NullPointerException || Main.debug)
        {
            ex.printStackTrace();
        }
    }
    public void addTask(final Runnable task)
    {
        synchronized(tasks)
        {
            tasks.add(task);
            tasks.notify();
        }
    }
    public void processTasks()
    {
        for(Runnable r : (ArrayList<Runnable>)tasks.clone())
        {
            tasks.remove(r);
            if(r != null)
            {
                Main.getScriptContext().run(r);
            }
            if(state.stopped == true)
                return;
        }
    }
}
